﻿using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
using Microsoft.Practices.Prism.PubSubEvents;
using Mitosoft.Definitions.Events;
using Prism.Common.Interfaces;
using Microsoft.Practices.Prism.Commands;
using Mitosoft.Definitions.ViewModels;
using Prism.Views;

namespace Prism.ViewModels
{
  /// <summary>
  /// View model used for <see cref="TextFileReaderAppMainView"/>
  /// </summary>
  public class TextFileReaderAppMainViewModel : BaseViewModel
  {
    #region fields

    /// <summary>
    /// Represents the service responsible for application wide stuff.
    /// </summary>
    protected IApplicationManagerService _applicationManagerService;

    /// <summary>
    /// Represents <see cref="ShutDownCommand"/>
    /// </summary>
    protected ICommand _shutDownCommand;

    /// <summary>
    /// Represents the event aggregator.
    /// </summary>
    protected IEventAggregator _eventAggregator;

    /// <summary>
    /// Represents <see cref="ZoomViewModel"/>
    /// </summary>
    protected ZoomViewModel _zoomViewModel;

    #endregion

    #region constructor(s)

    /// <summary>
    /// Creates a new <see cref="TextFileReaderAppMainViewModel"/> instance.
    /// </summary>
    /// <param name="applicationManagerService">Represents <see cref="IApplicationManagerService"/></param>
    /// <param name="eventAggregator">Represents the event aggregator.</param>
    public TextFileReaderAppMainViewModel(
      IApplicationManagerService applicationManagerService,
      IEventAggregator eventAggregator)
    {
      _applicationManagerService = applicationManagerService;
      _eventAggregator = eventAggregator;

      _eventAggregator.GetEvent<ApplicationZoomFactorChangedEvent>()
        .Subscribe(OnApplicationZoomFactorChangedEvent);
    }

    #endregion

    #region properties

    /// <summary>
    /// Represents the view model containing all needed for zooming.
    /// </summary>
    public ZoomViewModel ZoomViewModel
    {
      get
      {
        if (_zoomViewModel == null)
        {
          _zoomViewModel = new ZoomViewModel();
          _zoomViewModel.PropertyChanged += ZoomViewModelPropertyChanged;
        }

        return _zoomViewModel;
      }
    }


    /// <summary>
    /// Represents the command used to shut down the application.
    /// </summary>
    public ICommand ShutDownCommand
    {
      get
      {
        return
          _shutDownCommand ??
            (_shutDownCommand =
              new DelegateCommand(
                  OnShutDownCommandExecuted, 
                  CanExecuteShutDownCommand));
      }
    }

    #endregion

    #region methods

    /// <summary>
    /// Listens on the event occuring when the application zoom factor changes.
    /// </summary>
    /// <param name="zoomFactor">Represents the new zoom factor.</param>
    protected void OnApplicationZoomFactorChangedEvent(double zoomFactor)
    {
      ZoomViewModel.ZoomFactor = zoomFactor;
    }

    /// <summary>
    /// Disposes this object.
    /// </summary>
    /// <param name="isDisposing">Represents whether this object is disposing.</param>
    protected override void Dispose(bool isDisposing)
    {
      if (_isDisposed) return;

      if (isDisposing)
      {
        #region dispose managed resources

        _eventAggregator.GetEvent<ApplicationZoomFactorChangedEvent>().Unsubscribe(
          OnApplicationZoomFactorChangedEvent);

        if (ZoomViewModel != null)
        {
          _zoomViewModel.PropertyChanged -= ZoomViewModelPropertyChanged;
          _zoomViewModel.Dispose();
          _zoomViewModel = null;
        }

        #endregion
      }

      #region clean up unmanaged resources

      #endregion

      _isDisposed = true;
    }

    /// <summary>
    /// Occurs when a property of <see cref="ZoomViewModel"/> changes.
    /// </summary>
    /// <param name="sender">Not used.</param>
    /// <param name="e">Used to determine the name of the changed property.</param>
    protected void ZoomViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
      if (e.PropertyName == "ZoomFactor")
        _applicationManagerService.ZoomFactor = ZoomViewModel.ZoomFactor;

      // ReSharper disable once ExplicitCallerInfoArgument
      HandlePropertyChanged("ZoomViewModel");
    }

    /// <summary>
    /// Returns whether <see cref="ShutDownCommand"/> can be executed.
    /// </summary>
    /// <returns>True if <see cref="ShutDownCommand"/> can be executed.</returns>
    protected bool CanExecuteShutDownCommand()
    {
      return _applicationManagerService.ShutDownApplicationCommand.CanExecute(new CancelEventArgs());
    }

    /// <summary>
    /// <see cref="ShutDownCommand"/> shall be executed.
    /// </summary>
    protected void OnShutDownCommandExecuted()
    {
      _applicationManagerService.ApplicationIsShuttingDown = true;

      var cancelEventArgs = new CancelEventArgs(cancel: true);
      _applicationManagerService.ShutDownApplicationCommand.Execute(cancelEventArgs);
      if (cancelEventArgs.Cancel)
      {
        _applicationManagerService.ApplicationIsShuttingDown = false;
        return;
      } 

      Application.Current.MainWindow.Close();
    }

    #endregion
  }
}
